package com.rtsapp.server.network.protocol.command;

import com.rtsapp.server.common.ByteBuffer;
import com.rtsapp.server.common.IByteBuffer;
import com.rtsapp.server.logger.Logger;
import com.rtsapp.server.monitor.TimeoutMonitorTask;
import com.rtsapp.server.network.protocol.ProtocolInHandler;
import com.rtsapp.server.network.session.Session;
import com.rtsapp.server.profiling.NetworkProfilling;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;

import java.util.HashMap;
import java.util.Map;


public class AbstractCommandInHandler extends ProtocolInHandler implements ICommandHandlerRegister {

    private static final Logger LOGGER = com.rtsapp.server.logger.LoggerFactory.getLogger(AbstractCommandInHandler.class);

    private Map<Integer, ICommandHandler> processorMap = new HashMap<Integer, ICommandHandler>();


    public void registerCommandHandler(Integer moduleId, ICommandHandler processor) {
        processorMap.put(moduleId, processor);
    }

    public void unregisterCommandHandler(Integer moduleId) {
        if (processorMap.containsKey(moduleId)) {
            processorMap.remove(moduleId);
        }
    }

    public ICommandHandler getCommandHandler(int moduleId) {

        int commandType = ((moduleId >> 16) & 0x00FF);

        return processorMap.get(commandType);

    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {


        if (msg instanceof ByteBuf) {


            ByteBuf data = (ByteBuf) msg;
            int bytes = data.readableBytes();

            try {

                TimeoutMonitorTask.startProcess();


                ByteBuffer buffer = new ByteBuffer(data);

                Session session = sessionManager.getSession(ctx.channel());

                if (session != null) {

                    if (processMessageHead(session, buffer)) {
                        processMessageBody(session, buffer);
                    }

                } else {
                    LOGGER.error("[session] sessionManager.getSession 返回null, 请仔细检查为什么该channel为什么没有Session:channel={} ", ctx.channel());
                }

            } catch (Throwable ex) {
                LOGGER.error("数据包处理错误", ex);
            } finally {

                TimeoutMonitorTask.endProcess();

                //释放引用计数
                data.release();

                NetworkProfilling.getInstance().proflingInput(bytes);
            }

        } else {
            LOGGER.info("channelRead msg 不是ByteBuf..");
        }

    }


    public boolean processMessageHead(Session session, IByteBuffer buffer) {
        return true;
    }


    public void processMessageBody(Session session, IByteBuffer buffer) {

        int commandId = buffer.getInt(buffer.readerIndex());
        ICommandHandler commandHandler = getCommandHandler(commandId);

        if (commandHandler != null) {

            commandHandler.execute(commandId, session, buffer);

        } else {
            LOGGER.info("no handler find for commandId: 0x" + Integer.toHexString(commandId).toUpperCase());
        }

    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        if (cause.getMessage().equals("Worker reset by peer")) {
            LOGGER.warn("Worker reset by peer");
            return;
        }
        if (cause.getMessage().equals("Connection reset by peer")) {
            LOGGER.warn("Connection reset by peer");
            return;
        }
        if (cause.getMessage().equals("readAddress() failed: Connection timed out")) {
            LOGGER.warn("readAddress() failed: Connection timed out");
            return;
        }
        if (cause.getMessage().equals("syscall:read(...)() failed: Connection reset by peer")) {
            LOGGER.warn("syscall:read(...)() failed: Connection reset by peer");
            return;
        }

        LOGGER.error("检测到Handler未捕获的异常", cause);
    }


}
